#include "mainwindow.h"
#include "dialog.h"
#include "testDialog.h"
#include <QtGui>

//! Constructs the main window of the application.
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{

    dialog = new Dialog();
    dialog->setWindow(this);


    testDialog = new TestDialog(this);
    testDialog->setWindow(this);

    stackedLayout=new QStackedLayout;
    placeholder= new QWidget();
    placeholder->setLayout(stackedLayout);
    stackedLayout->addWidget(dialog);
    stackedLayout->addWidget(testDialog);
           stackedLayout->setCurrentIndex(0);
            //dialog;

    //need to do all this mess with the stacked layout because setCentralWidget
    //takes ownership of the widget pointer and deletes it
    //when you set another central widget so just changing the central widget won't do

    setCentralWidget(placeholder);

    modeLabel= new QLabel("<b>Code generation</b>");
    modeLabel->setToolTip("Use the menu to switch mode");

    createActions();
    createMenus();
    createStatusBar();
    setWindowTitle("drvAutogen");
    setCurrentFile("");


}


//! Invoked when the closeEvent is triggered.
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (maybeSave()) {
        event->accept();
    } else {
        event->ignore();
    }
}

//! Opens a new empty instance.
bool MainWindow::newFile()
{
    if (maybeSave()) {

        genModeAct->setChecked(true);

        dialog = new Dialog();
        dialog->setWindow(this);


        testDialog = new TestDialog(this);
        testDialog->setWindow(this);



        stackedLayout=new QStackedLayout;
        placeholder= new QWidget();
        placeholder->setLayout(stackedLayout);
        stackedLayout->addWidget(dialog);
        stackedLayout->addWidget(testDialog);
        stackedLayout->setCurrentIndex(0);

        setCentralWidget(placeholder);


        setCurrentFile("");
        return true;


    }else
        return false;
}

//! Opens a new empty instance.
void MainWindow::openXmlFile()
{
    if(!newFile())
        return;

    QString fileName = QFileDialog::getOpenFileName(this,"Select a suitable XML file");
    if (fileName.isEmpty())
        return;

    dialog->readXML(fileName);

}




//! Saves the layout as an XML file with the name provided by the user.
bool MainWindow::saveXmlAs()
{
    QString fileName = QFileDialog::getSaveFileName(this);
    if (fileName.isEmpty())
        return false;

    return saveXml(fileName);
}

//! Saves the layout as an XML file with the given filename.
bool MainWindow::saveXml(const QString fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("drvAutogen"),
                             tr("Cannot write file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return false;
    }

    dialog->generateXML(fileName);
    setCurrentFile(fileName);
    dialog->isSaved();
    statusBar()->showMessage(tr("File saved"), 2000);
    return true;
}

//! Saves the layout on the current XML file.
bool MainWindow::save()
{
    if (curFile.isEmpty()) {
        return saveXmlAs();
    } else {
        return saveXml(curFile);
    }
}

//! Generates the .h files calling MainWindow::inGenCode()
void MainWindow::genCode()
{
    if (curFile.isEmpty()) {
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("drvAutogen"),
                                   tr("You need to save the layout as an XML file before generating the code"),
                                   QMessageBox::Save | QMessageBox::Cancel);
        if (ret == QMessageBox::Save)
            {if(!saveXmlAs())//se non salva
                return;}
        else if (ret == QMessageBox::Cancel)
            return;
    } else {
        saveXml(curFile);
    }

    bool b=inGenCode();

    if(b==true)
        statusBar()->showMessage(tr("Code generated correctly"),2000);
    else
        statusBar()->showMessage(statusBar()->currentMessage().append("Code could not be generated"),5000);

    
}

//! Calls the command line tool and generates .h files
bool MainWindow::inGenCode(){//TODO: generate in custom folder

    QString dirName = QFileDialog::getExistingDirectory(this,tr("Select a directory to save the code in"),QString(""),QFileDialog::ShowDirsOnly);
    if (dirName.isEmpty())
        return false;


    QString program = "./drvautogen/drvautogen";
    QStringList arguments;
    arguments << curFile;
    arguments << dirName;

    QProcess *myProcess = new QProcess();
    myProcess->start(program, arguments);

    if(!myProcess->waitForStarted())
    {statusBar()->showMessage(tr("Tool for code generation not found. "),5000);
        return false;}

    myProcess->waitForFinished(5000);

    if(myProcess->exitCode()==0)
        return true;
    else
    {statusBar()->showMessage(tr("Error generating the code. "),5000);
        return false;}


}



//! Creates the Menus of the main window.
void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(openAct);
    fileMenu->addAction(genCodeAct);
    fileMenu->addAction(saveXmlAct);
    fileMenu->addAction(saveXmlAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    modeMenu = menuBar()->addMenu(tr("&Mode"));
    modeMenu->addAction(genModeAct);
    modeMenu->addAction(testModeAct);
//    modeMenu->addSeparator();



    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

//! Creates the Actions.
void MainWindow::createActions()
{
    newAct = new QAction(tr("&New"), this);
    newAct->setShortcuts(QKeySequence::New);
    newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

    openAct = new QAction(tr("&Open..."), this);
    openAct->setShortcuts(QKeySequence::Open);
    openAct->setStatusTip(tr("Open an existing XML layout file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(openXmlFile()));

    genCodeAct = new QAction(tr("&Generate code"), this);
    genCodeAct->setShortcuts(QKeySequence::Print);
    genCodeAct->setStatusTip(tr("Generate C code from the layout"));
    connect(genCodeAct, SIGNAL(triggered()), this, SLOT(genCode()));


    saveXmlAct = new QAction(tr("&Save XML"), this);
    saveXmlAct->setShortcuts(QKeySequence::Save);
    saveXmlAct->setStatusTip(tr("Save the changes"));
    connect(saveXmlAct, SIGNAL(triggered()), this, SLOT(save()));

    saveXmlAsAct = new QAction(tr("Save XML &As"), this);
    saveXmlAsAct->setShortcuts(QKeySequence::SaveAs);
    saveXmlAsAct->setStatusTip(tr("Save the layout as a new XML file"));
    connect(saveXmlAsAct, SIGNAL(triggered()), this, SLOT(saveXmlAs()));

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setShortcuts(QKeySequence::Quit);
    exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));



    genModeAct = new QAction(tr("&Code generation"), this);
    //genCodeAct->setShortcuts(QKeySequence::Print);
    genModeAct->setStatusTip(tr("Switch to code generation mode"));
    genModeAct->setCheckable(true);
    connect(genModeAct, SIGNAL(toggled(bool)), this, SLOT(changeMode()));

    testModeAct = new QAction(tr("&Test generation"), this);
    //genCodeAct->setShortcuts(QKeySequence::Print);
    testModeAct->setStatusTip(tr("Switch to test generation mode"));
    testModeAct->setCheckable(true);
    connect(testModeAct, SIGNAL(toggled(bool)), this, SLOT(changeMode()));

    modeActGroup= new QActionGroup(this);
    modeActGroup->addAction(genModeAct);
    modeActGroup->addAction(testModeAct);
    genModeAct->setChecked(true);

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));


    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

}



//! Slot called when the mode changes
void MainWindow::changeMode()
{


    if(genModeAct->isChecked()){
        stackedLayout->setCurrentIndex(0);
    modeLabel->setText("<b>Code generation</b>");
    }
    else{
        testDialog->updateComboBox();
        stackedLayout->setCurrentIndex(1);
        modeLabel->setText("<b>Test generation</b>");


    
    
    }



}



//! Pops up a message box with a brief text about the application.
void MainWindow::about()
{
    QMessageBox::about(this, tr("About drvAutogen"),
                       tr("<b>drvAutogen</b> allows the user to describe the layout of a peripheral and save it as an XML file. \n"
                          "The tool then generates two C header files containing the defines and macros necessary to access "
                          "and control the registers of the device."));
}

//! Pops up a message box asking to save or discard if the layout has been modified since last save.
bool MainWindow::maybeSave()
{
    if (dialog->isModified()) {
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("drvAutogen"),
                                   tr("The current layout has unsaved changes.\n"
                                      "Do you want to save your changes before proceeding?"),
                                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        if (ret == QMessageBox::Save)
            return save();
        else if (ret == QMessageBox::Cancel)
            return false;
    }
    return true;
}

//! Sets current file as fileName.
void MainWindow::setCurrentFile(const QString &fileName)
{
    curFile = fileName;
    setWindowModified(false);
}

//! Creates status bar.
void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready: add a register to begin"),5000);
    statusBar()->addPermanentWidget(modeLabel);

}

//! Adds an asterisk to the window title if the layout has been modified
void MainWindow::hasChanged(){
    if(curFile.isEmpty())
        setWindowTitle("drvAutogen - <unsaved>");
    else{
        QString x="drvAutogen - ";
        x.append(QFileInfo(curFile).fileName());
        x.append("*");
        setWindowTitle(x);
    }

    testDialog->hasChanged();

}

//! Sets the window title to drvAutogen + fileName
void MainWindow::saved(){
    QString x="drvAutogen - ";
    x.append(QFileInfo(curFile).fileName());
    setWindowTitle(x);
}
